<template>
    <div class="flex flex-1 overflow-hidden">
        <el-scrollbar class="retrieval-forms">
            <el-form>
                <el-form-item>
                    <el-input
                        v-model="question"
                        type="textarea"
                        :rows="12"
                        placeholder="请输入测试文本"
                    />
                </el-form-item>
                <el-form-item>
                    <div class="flex justify-end w-full">
                        <el-button @click="searchConf.show = true">
                            <el-image
                                class="w-[16px] h-[16px] mr-1.5"
                                :src="searchIcon[searchConf.search_mode].icon"
                            />
                            <span>{{ searchIcon[searchConf.search_mode].name }}</span>
                        </el-button>
                        <el-button
                            :loading="loading"
                            :disabled="know.power < permissionEnum.EDIT"
                            type="primary"
                            @click="handleSearch"
                        >测试</el-button>
                    </div>
                </el-form-item>
            </el-form>
        </el-scrollbar>

        <el-scrollbar class="retrieval-recall">
            <div class="p-4">
                <div class="mb-2 flex items-center text-lg">
                    <icon name="el-icon-Memo" :size="18" />
                    <span class="ml-1">测试结果</span>
                    <span v-if="searchTime" class="ml-1">({{ searchTime }})</span>
                </div>
                <div v-for="(item, index) in dataList" :key="index" class="recall-item">
                    <div class="flex items-center justify-between mb-3">
                        <span class="serial">
                            #{{ index + 1 }} | {{ searchIcon[searchConf.search_mode].name }}
                        </span>

                        <div class="flex items-center gap-2">
                            <div v-if="item.rerank_score >= 0">
                                <span class="text-xs text-tx-secondary mr-1.5">
                                    重排分数: {{ item.full_score }}
                                </span>
                            </div>
                            <div v-if="item.full_score >= 0">
                                <span class="text-xs text-tx-secondary mr-1.5">
                                    全文检索: {{ item.full_score }}
                                </span>
                            </div>
                            <div v-if="item.emb_score >= 0 && searchConf.search_mode != 'similar'">
                                <span class="text-xs text-tx-secondary mr-1.5">
                                    语义检索: {{ item.emb_score }}
                                </span>
                            </div>
                            <div
                                v-if="item.emb_score >= 0 && searchConf.search_mode === 'similar'"
                                class="flex items-center w-[200px]"
                            >
                                <span class="text-xs text-tx-secondary mr-1.5">语义检索: </span>
                                <el-progress
                                    class="flex-1"
                                    :percentage="Math.abs(item.emb_score / 1) * 100"
                                >
                                    <span class="text-sm">{{ Math.abs(item.emb_score).toFixed(5) }}</span>
                                </el-progress>
                            </div>
                        </div>
                    </div>
                    <div class="text-tx-regular">{{ item.question }}</div>
                    <div class="flex items-center mt-3">
                        <div class="flex items-center">
                            <icon name="svg-icon-Char" color="var(--el-text-color-secondary)" />
                            <span class="ml-1 text-xs text-tx-secondary">{{ item.character }}</span>
                        </div>
                        <nuxt-link
                            v-if="item.file?.path"
                            class="ml-3 underline text-tx-regular hover:text-tx-primary"
                            :to="item.file.path"
                            :external="true"
                            target="_blank"
                        >
                            {{ item.file.name }}
                        </nuxt-link>
                    </div>
                </div>
                <div v-if="dataList.length <= 0" class="mt-10">
                    <el-empty :image-size="140" description="测试结果展示位置" />
                </div>
            </div>
        </el-scrollbar>

        <!-- 知识库参数 -->
        <popup-know-params
            :show="searchConf.show"
            :mode="searchConf.search_mode"
            :tokens="searchConf.search_tokens"
            :similar="searchConf.search_similar"
            :ranking="searchConf.ranking_status"
            :optimize="searchConf.optimize_ask"
            :ranking-model="searchConf.ranking_model"
            :optimize-model="searchConf.optimize_model"
            @close="searchConf.show = false"
            @confirm="handleConfirmConf"
        />
    </div>
</template>

<script setup lang="ts">
import { permissionEnum } from '~/enums/app'
import feedback from '~/utils/feedback'
import knowDatasetApi from '~/api/agent/know/dataset'
import PopupKnowParams from '../../_components/popup-know-params.vue'
import semaIcon from '~/assets/image/search_semantics.png'
import fullIcon from '~/assets/image/search_full.png'
import mixIcon from '~/assets/image/search_mix.png'

const props = withDefaults(
    defineProps<{
        know: Record<string, any>
    }>(),
    {}
)

// 检索状态
const loading = ref<boolean>()

// 检索问题
const question = ref<string>('')

// 检索数据
const dataList = ref<KnowDatasetTestingResponse[]>([])

// 检索时间
const searchTime = ref<string>('')

// 检索配置
const searchConf = ref({
    show: false,
    search_mode: 'similar',
    search_tokens: 5000,
    search_similar: 0,
    ranking_status: 0,
    ranking_score: 0,
    ranking_model: '',
    optimize_ask: 0,
    optimize_model: ''
})

// 检索图标
const searchIcon: any = {
    'similar': {name: '语义检索', icon: semaIcon},
    'full': {name: '全文检索', icon: fullIcon},
    'mix': {name: '混合检索', icon: mixIcon}
}

/**
 * 处理配置
 *
 * @param config
 * @author zero
 */
const handleConfirmConf = (config: any) => {
    searchConf.value.search_mode = config.mode
    searchConf.value.search_tokens = config.tokens
    searchConf.value.search_similar = config.similar

    searchConf.value.ranking_status = config.ranking ? 1 : 0
    searchConf.value.optimize_ask = config.optimize ? 1 : 0
    searchConf.value.ranking_model = config.ranking_model
    searchConf.value.optimize_model = config.optimize_model
    searchConf.value.show = false
}

/**
 * 发起检索
 */
const handleSearch = async () => {
    searchTime.value = ''
    const startTime = performance.now()

    if (!question.value) {
        return feedback.msgError('请输入测试文本')
    }

    loading.value = true
    dataList.value = await knowDatasetApi.testing({
        kb: props.know.code,
        text: question.value,
        search_mode: searchConf.value.search_mode,
        search_tokens: searchConf.value.search_tokens,
        search_similar: searchConf.value.search_similar,
        ranking_status: searchConf.value.ranking_status,
        ranking_score: searchConf.value.ranking_score,
        ranking_model: searchConf.value.ranking_model,
        optimize_ask: searchConf.value.optimize_ask,
        optimize_model: searchConf.value.optimize_model
    }).finally(() => {
        loading.value = false
    })

    if (dataList.value.length > 0) {
        const endTime = performance.now()
        const durationInSeconds = (endTime - startTime) / 1000
        searchTime.value = durationInSeconds.toFixed(3) + 's'
    } else {
        feedback.msgWarning('搜索结果为空')
    }
}
</script>

<style scoped lang="scss">
.retrieval-forms {
    flex: 1;
    max-width: 460px;
    padding: 16px;
    overflow: hidden;
    background-color: var(--el-color-light);
    border-right: 1px solid var(--el-border-color-light);
}

.retrieval-recall {
    flex: 1;
    .recall-item {
        padding: 12px;
        margin-bottom: 12px;
        background-color: var(--el-bg-color-page);
        border-radius: 12px;
        .serial {
            padding-inline: 5px;
            margin-right: 2px;
            font-size: 12px;
            color: var(--el-color-primary);
            background: var(--el-color-primary-light-9);
            border-color: var(--el-color-primary-light-3);
            border-width: 1px;
            border-radius: 6px;
        }
    }
    :deep(.el-progress-bar__outer) {
        background-color: var(--el-color-primary-light-8)
    }
}
</style>
